#ifndef __WIZ_ALGEBRA_QUATERNION_CORE_HPP__SHANHAOBO_19800429__
#define __WIZ_ALGEBRA_QUATERNION_CORE_HPP__SHANHAOBO_19800429__

#include "../../Utils/WizAlgebraUtils.hpp"
#include "../Vector3/WizAlgebraVector3.hpp"
#include "./WizAlgebraQuaternionBase.hpp"

namespace Wiz
{
    namespace Quat
    {
        namespace Core
        {
            template<class ElementT>
            struct Type : public ::Wiz::Quat::Base::Type<ElementT>
            {
                typedef ::Wiz::Quat::Base::Type<tElement>       tSuper;
                typedef Type<tElement>                          tThis;
                typedef ::Wiz::Vector3::Type<tElement>          tVector3;

                ////////////////////////////////////////////////////////////////
                Type()
                {}
                Type(const tElement& InW, const tElement& InX, const tElement& InY, const tElement& InZ) : tSuper(InW, InX, InY, InZ)
                {}
                Type(const tElement& InEle) : tSuper(InEle)
                {}
                Type(const tSuper& InOther) : tSuper(InOther)
                {}
                ////////////////////////////////////////////////////////////////

                tVector3& Vec3()
                {
                    return ::Wiz::Cast::Force<tVector3>(this->xyz);
                }

                tVector3& Vec3() const
                {
                    return ::Wiz::Cast::Force<tVector3>(this->xyz);
                }

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Add(tThis& OutQuat, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& Add(tThis& OutQuat, tThisIn InQuat, const tElement& InEle);

                WIZ_INLINE static tThis& AddAssign(tThis& InOutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& AddAssign(tThis& InOutQuat, const tElement& InEle);
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Subtract(tThis& OutQuat, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& Subtract(tThis& OutQuat, tThisIn InQuat, const tElement& InEle);

                WIZ_INLINE static tThis& SubtractAssign(tThis& InOutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& SubtractAssign(tThis& InOutQuat, const tElement& InEle);
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Multiply(tThis& OutQuat, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& Multiply(tThis& OutQuat, tThisIn InQuat, const tElement& InEle);
                WIZ_INLINE static tThis& Multiply(tThis& OutQuat, tThisIn InQuat, const tVector3& InVec);

                WIZ_INLINE static tThis& MultiplyAssign(tThis& InOutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& MultiplyAssign(tThis& InOutQuat, const tElement& InEle);
                WIZ_INLINE static tThis& MultiplyAssign(tThis& InOutQuat, const tVector3& InVec);
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Identity(tThisIn InQuat);
                WIZ_INLINE static tElement SqrLength(tThisIn InQuat);
                WIZ_INLINE static tElement Length(tThisIn InQuat);
                WIZ_INLINE static tThis& Normalize(tThis& OutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& Normalize(tThis& InOutQuat);
                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Conjugate(tThis& OutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& Conjugate(tThis& InOutQuat);

                WIZ_INLINE static tThis& Inverse(tThis& OutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& Inverse(tThis& InOutQuat);

                WIZ_INLINE static tThis& InverseSafe(tThis& OutQuat, tThisIn InQuat);
                WIZ_INLINE static tThis& InverseSafe(tThis& InOutQuat);

                WIZ_INLINE static tElement Dot(tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tElement Angle(tThisIn InQuat1, tThisIn InQuat2);
                //////////////////////////////////////////////////////////////////////////
                template<class Matrix33T>
                WIZ_INLINE static ::Wiz::Void::Type ToMatrix(Matrix33T& OutMat, tThisIn InQuat);

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tVector3& Rotate(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& RotateSafe(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& RotateFast(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& RotateFastSafe(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);

                WIZ_INLINE static tVector3& InverseRotate(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& InverseRotateSafe(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& InverseRotateFast(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                WIZ_INLINE static tVector3& InverseRotateFastSafe(tVector3& OutVec, tThisIn InQuat, const tVector3& InVec);
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                WIZ_INLINE static tThis& Interpolate(tThis& OutQuat, ::Wiz::Real::In Coeff1, tThisIn InQuat1, ::Wiz::Real::In Coeff2, tThisIn InQuat2);
                WIZ_INLINE static tThis& Lerp(tThis& OutQuat, ::Wiz::Real::In t, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& Slerp(tThis& OutQuat, ::Wiz::Real::In t, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& SlerpShortestPath(tThis& OutQuat, ::Wiz::Real::In t, tThisIn InQuat1, tThisIn InQuat2);
                WIZ_INLINE static tThis& Squad(tThis& OutQuat, ::Wiz::Real::In t, tThisIn InQuat1, tThisIn InQuat2, tThisIn C1, tThisIn C2);
                //////////////////////////////////////////////////////////////////////////
            };
        } /// end of namespace Core
    } /// end of namespace Quat
} /// end of namespace Wiz

#ifndef __WIZ_ALGEBRA_QUATERNION_CORE_INL__SHANHAOBO_19800429__
#define __WIZ_ALGEBRA_QUATERNION_CORE_INL__SHANHAOBO_19800429__
#include "./WizAlgebraQuaternionCore.inl"
#endif /*__WIZ_ALGEBRA_QUATERNION_CORE_INL__SHANHAOBO_19800429__*/

#endif /*__WIZ_ALGEBRA_QUATERNION_CORE_HPP__SHANHAOBO_19800429__*/
